package handlers

import (
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type User struct {
	ID           uint           `json:"id" gorm:"primaryKey"`
	CreatedAt    time.Time      `json:"created_at"`
	UpdatedAt    time.Time      `json:"updated_at"`
	DeletedAt    gorm.DeletedAt `json:"-" gorm:"index"`
	Name         string         `json:"name" binding:"required"`
	Email        string         `json:"email" gorm:"uniqueIndex" binding:"required,email"`
	PasswordHash string         `json:"-"`
	Role         string         `json:"role" gorm:"default:member"` // member | librarian | admin
	BorrowLimit  int            `json:"borrow_limit" gorm:"default:5"`
	Active       bool           `json:"active" gorm:"default:true"`
}

func RegisterUser(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		var input struct {
			Name     string `json:"name" binding:"required"`
			Email    string `json:"email" binding:"required,email"`
			Password string `json:"password" binding:"required,min=6"`
		}
		if err := c.ShouldBindJSON(&input); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		hashed, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "密码处理失败"})
			return
		}

		u := User{
			Name:         input.Name,
			Email:        input.Email,
			PasswordHash: string(hashed),
			Role:         "member",
		}

		if err := db.Create(&u).Error; err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "创建用户失败"})
			return
		}

		u.PasswordHash = ""
		c.JSON(http.StatusCreated, u)
	}
}

func UpdateUser(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		id := c.Param("id")
		var user User
		if err := db.First(&user, id).Error; err != nil {
			c.JSON(http.StatusNotFound, gin.H{"error": "未找到用户"})
			return
		}

		var input struct {
			Name        *string `json:"name"`
			Password    *string `json:"password"`
			BorrowLimit *int    `json:"borrow_limit"`
			Role        *string `json:"role"`
			Active      *bool   `json:"active"`
		}
		if err := c.ShouldBindJSON(&input); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		updates := map[string]interface{}{}
		if input.Name != nil {
			updates["name"] = *input.Name
		}
		if input.BorrowLimit != nil {
			updates["borrow_limit"] = *input.BorrowLimit
		}
		if input.Active != nil {
			updates["active"] = *input.Active
		}

		if input.Password != nil {
			hashed, _ := bcrypt.GenerateFromPassword([]byte(*input.Password), bcrypt.DefaultCost)
			updates["password_hash"] = string(hashed)
		}

		if input.Role != nil {
			callerRole := c.GetHeader("X-User-Role")
			if callerRole != "admin" {
				c.JSON(http.StatusForbidden, gin.H{"error": "无权限修改角色"})
				return
			}
			updates["role"] = *input.Role
		}

		if len(updates) > 0 {
			if err := db.Model(&user).Updates(updates).Error; err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "更新失败"})
				return
			}
		}

		user.PasswordHash = ""
		c.JSON(http.StatusOK, user)
	}
}

func ListUsers(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		var users []User
		page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
		size, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
		if page < 1 {
			page = 1
		}
		if size < 1 || size > 100 {
			size = 20
		}
		q := db.Offset((page - 1) * size).Limit(size)
		if role := c.Query("role"); role != "" {
			q = q.Where("role = ?", role)
		}
		if err := q.Find(&users).Error; err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
			return
		}
		for i := range users {
			users[i].PasswordHash = ""
		}
		c.JSON(http.StatusOK, users)
	}
}
